
AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )
include( 'shared.lua' )

CreateConVar('swep_weldball_gravity', 1000)
CreateConVar('swep_weldball_range', 1500)
CreateConVar('swep_weldball_hurtrange', 150)
CreateConVar('swep_weldball_weldrange', 150)
CreateConVar('swep_weldball_quickwelds', 0)
CreateConVar('swep_weldball_removegrav', 0)

function ENT:Statue( ent )
	if (!ent) then return false end
	if (!ent:IsValid()) then return false end
	if (ent:IsPlayer()) then return false end	
	if (ent:GetClass() != "prop_ragdoll" ) then return false end
	if (ent:GetPhysicsObjectCount() < 2 ) then return false end
	if ( ent:GetTable().StatueInfo != nil )  then return false end
	
	ent:GetTable().StatueInfo = {}
	ent:GetTable().StatueInfo.Welds = {}
	
	local bones = ent:GetPhysicsObjectCount()
	local forcelimit = 0
	
	for bone=1, bones do
		local bone1 = bone - 1
		local bone2 = bones - bone
		if ( !ent:GetTable().StatueInfo.Welds[bone2] ) then
			local constraint1 = constraint.Weld( ent, ent, bone1, bone2, forcelimit )
			if ( constraint1 ) then
				ent:GetTable().StatueInfo.Welds[bone1] = constraint1
				self.Entity:GetOwner():AddCleanup( "constraints", constraint1 )
			end
		end
		local constraint2 = constraint.Weld( ent, ent, bone1, 0, forcelimit )
		if ( constraint2 ) then
			ent:GetTable().StatueInfo.Welds[bone1+bones] = constraint2
			self.Entity:GetOwner():AddCleanup( "constraints", constraint2 )
		end
	end
end

function ENT:Initialize()
	self.Entity:SetModel( "models/weapons/w_gravball.mdl" )
	
	self.Entity:PhysicsInit( SOLID_VPHYSICS )
    self.Entity:SetMoveType( MOVETYPE_VPHYSICS )   
    self.Entity:SetSolid( SOLID_VPHYSICS )
	
	local phys = self.Entity:GetPhysicsObject()
	if (phys:IsValid()) then
		phys:Wake()
	end
	
	util.PrecacheSound( "weapons/physcannon/superphys_hold_loop.wav" )
	util.PrecacheSound( "weapons/physcannon/superphys_launch4.wav" )
	util.PrecacheSound( "weapons/Irifle/irifle_fire2.wav" )
	util.PrecacheSound( "physics/metal/metal_grenade_impact_soft3.wav" )
	self.SuckLoop = CreateSound(self.Entity, Sound( "weapons/physcannon/superphys_hold_loop.wav" ))
	
	util.SpriteTrail( self.Entity, 0, Color( 255, 20, 20 ), false, 10, 1, 2, 1/( 15 + 1 )*0.5, "trails/laser.vmt")
	
	self.HurtRange = GetConVarNumber('swep_weldball_hurtrange')
	self.WeldRange = GetConVarNumber('swep_weldball_weldrange')
	self.MaxRange = GetConVarNumber('swep_weldball_range')
	self.G = GetConVarNumber('swep_weldball_gravity')
	self.QuickWelds = (GetConVarNumber('swep_weldball_quickwelds')>0)
	self.NoCollide = (GetConVarNumber('swep_weldball_nocollide')>0)
	self.RemoveGravity = (GetConVarNumber('swep_weldball_removegrav')>0)
	
	self:SetCurrentState(0)
end

function ENT:ExplodeAndWeld()
	if !self or !self:IsValid() then return end
	self.SuckLoop:Stop()
	self.Entity:EmitSound( "weapons/physcannon/superphys_launch4.wav",150,200 )

	local effectdata = EffectData()
		effectdata:SetEntity( self.Entity )
		effectdata:SetOrigin( self.Entity:GetPos() )
		effectdata:SetScale( 1 )
		effectdata:SetMagnitude( 1 )
				
	util.Effect( "super_explosion", effectdata )
	
	local ent = ents.Create ("npc_weldball_proj_dead")
	ent:SetPos(self:GetPos())
	ent:SetAngles(self:GetAngles())
	ent:SetPhysicsAttacker(self.Entity:GetPhysicsAttacker())
	ent:SetOwner(self.Entity:GetOwner())
	ent:Spawn()
	ent:GetPhysicsObject():EnableMotion(false)
	
	local toweld,n = {},0
	for _,contact in pairs(ents.FindInSphere(self.Entity:GetPos(), self.MaxRange)) do
		local d = self.Entity:GetPos():Distance(contact:GetPos())
		
		if d<self.WeldRange and !contact:IsPlayer() and !contact:IsNPC() and contact:GetPhysicsObject() and contact:GetPhysicsObject():IsValid() then
			
			for i=0,contact:GetPhysicsObjectCount()-1 do contact:GetPhysicsObjectNum(i):EnableMotion(false) end
			
			self:Statue(contact)
			if self.QuickWelds then
				constraint.Weld( contact, ent, 0, 0, 0, false )
			end
			n = n+1
			toweld[n] = contact
			
			
			if contact:GetClass() ~= "npc_weldball_proj" then
				timer.Create("WeldballZapEffect"..contact:EntIndex(),0.1,20,function()
					local effectdata = EffectData()
						if !contact or !contact:IsValid() then return end
						effectdata:SetEntity( contact )
						effectdata:SetStart( contact:GetPos() )
						effectdata:SetOrigin( contact:GetPos() )
						effectdata:SetAngle( contact:GetAngles() )
						effectdata:SetScale( 15 )
						effectdata:SetMagnitude( 15 )
					util.Effect( "TeslaHitBoxes", effectdata )
				end)
			end
			
			for i=0,contact:GetPhysicsObjectCount()-1 do
				contact:GetPhysicsObjectNum(i):EnableMotion(true)
				if !self.RemoveGravity then contact:GetPhysicsObjectNum(i):EnableGravity(true) end
			end
		elseif contact:GetPhysicsObject() and contact:GetPhysicsObject():IsValid() then
			for i=0,contact:GetPhysicsObjectCount()-1 do contact:GetPhysicsObjectNum(i):EnableGravity(true) end
		end
	end
	
	for i=1,n do
		local contact = toweld[i]
		for j=i+1,n do
			if !self.QuickWelds then constraint.Weld( contact, toweld[j], 0, 0, 0, false ) end
			if self.NoCollide then constraint.NoCollide( contact, toweld[j], 0, 0 ) end
		end
	end
	
	
	
	ent:GetPhysicsObject():EnableMotion(true)
	self.Entity:Remove()
end

function ENT:Think()
	if self:GetCurrentState() == 0 then  -- Has just been thrown
		if self:GetVelocity():Length() < 22 then
			self.Entity:EmitSound( "weapons/Irifle/irifle_fire2.wav" )
			self.SuckLoop:PlayEx(80,200)
			
			local physobj = self:GetPhysicsObject()
			physobj:SetVelocity( Vector( 0, 0, 700 ) )
			timer.Simple( 0.5, physobj.EnableMotion, physobj, false )
			timer.Simple( 0.5, self.SetCurrentState, self, 1 )
			timer.Simple( 7, self.ExplodeAndWeld, self )
		end
	elseif self:GetCurrentState() == 1 then  -- Sucking props
		for _,contact in pairs(ents.FindInSphere(self.Entity:GetPos(), self.MaxRange)) do
		
			if contact:IsPlayer() or contact:IsNPC() then -- Kill players and NPCs in range
				local physobj = contact:GetPhysicsObject(i)
				local u = self:GetPos() - contact:GetPos()
				local d = u:Length()
				
				if physobj and physobj:IsValid() then
					u:Normalize()
					if contact:GetMoveType() == MOVETYPE_VPHYSICS then
						physobj:AddVelocity( FrameTime() * u * (2*physobj:GetVelocity():Length() + self.G) * (100000*physobj:GetMass())/(d^2) )
					else
						contact:SetVelocity( FrameTime() * u * (2*contact:GetVelocity():Length() + self.G) * (100000*(physobj:GetMass()/4))/(d^2) )
					end
				end
				
				if d<self.HurtRange then
					contact:TakeDamage(10000,self.Entity:GetOwner())
				end
			else
			
				for i=0,contact:GetPhysicsObjectCount()-1 do
					local physobj = contact:GetPhysicsObjectNum(i)
					if physobj and physobj:IsValid() then
						local u = self:GetPos() - contact:GetPos()
						local d = u:Length()
						u:Normalize()
						physobj:EnableGravity(false)
						physobj:AddVelocity( FrameTime() * u * (2*physobj:GetVelocity():Length() + self.G) * (100000*physobj:GetMass())/(d^2) )
					end
				end
			end
			
		end
	end
end

function ENT:PhysicsCollide( data, physobj )
	if self:GetVelocity():Length() > 150 then self.Entity:EmitSound( "physics/metal/metal_grenade_impact_soft3.wav" ) end
end

function ENT:OnTakeDamage( dmginfo )
	self.Entity:TakePhysicsDamage( dmginfo )
end
